home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / STARS.C < prev   
C/C++ Source or Header  |  1989-02-09  |  13KB  |  493 lines

  1. #include ":Includes:MemoryMgr.h"
  2. #include ":Includes:DeviceMgr.h"
  3. #include ":Includes:Quickdraw.h"
  4. #include ":Includes:WindowMgr.h"
  5. #include ":Includes:EventMgr.h"
  6.  
  7. int numStars = 500;        /* number of stars */
  8. int inUse = 0;            /* number actually in use */
  9. #define xyspan 8000        /* range of the xy space. */
  10. #define zspan 150    /* if you change this, change StarSize */
  11. typedef int **IntHandle;
  12. IntHandle theThrottle;    /* resource with permanent throttle setting */
  13.  
  14. /* Program to get those 'star trek" type stars.
  15.    Stars 1.3 by David Phillip Oster, in LightSpeed C
  16.    Arpa: oster@lapis.berkeley.edu
  17.    Usenet: ucbvax!lapis!oster
  18.    originally Aztec C v. 1.06H by Steve Hawley  6/12/86
  19.    heavily modified by 
  20.    David Oster June 13, 1986
  21.    David Oster June 14, 1986 - added throttle.
  22.    David Oster June 15, 1986 - added throttle memory.
  23.    David Oster June 17, 1986 - centered the copybits stars
  24.    David Oster June 18, 1986 - added hyper-space effect to throttle.
  25.  
  26.    Hawley says:
  27.    I'm very disappointed with the speed, as I've written a similar
  28.    program in 6502 assembly that handles 5 times as many stars
  29.    faster (this was on a 1 Mhz processor compared to the Mac's 8 Mhz).
  30.    My question is, is my C programming that bad or is Aztec C that
  31.    poor in performance? 
  32. Complaints, etc to:
  33. David Oster
  34. Usenet: ucbvax!ucblapis!oster
  35. ARPA:    oster%lapis@berkeley
  36. */
  37.  
  38. /*
  39. calling tree:
  40. main
  41.     closeDriver
  42.     doMain
  43.         RsrcID
  44.         update    - (the heart of the program)
  45.             StarSize
  46.             DrawStar
  47.                 FlipPixel
  48.         Throttle - ( for initialization )
  49.         SetThrottle
  50.             HyperThrottle
  51.                 HyperUpdate
  52.                     DrawStar
  53.                 Throttle
  54.                     rampUp
  55.                         DrawStar
  56.                     rampDn
  57.                         DrawStar
  58. */
  59.  
  60. void DrawStar(), HyperThrottle();
  61.  
  62. struct starRec {           /* define a star as an x,y,z point */
  63.         int y,x,z;            /* keep it compatible with a mac point */
  64. };
  65.  
  66. struct star {
  67.   struct starRec pos, draw;
  68. } *galaxy;
  69.  
  70. WindowPtr       myWindow;
  71.  
  72. /* abs - returns absolute value of its argument
  73.  */
  74. int abs(i)int i;{
  75.         if (i < 0) return(-i);
  76.         else return(i);
  77. }
  78.  
  79. /* 150 - 60 = 1
  80.     59 -  30 = 2
  81.     29 - 15 = 3
  82.     15 -   0 = 4 star size depends on distance. closer is bigger
  83.  */
  84. /* StarSize - map star's z into a small size.
  85.  */
  86.  
  87. int StarSize(z)int z;{
  88.   return z > 60 ? 1 : (z > 30 ? 2 : (z > 15 ? 3 : 4));
  89. }
  90.  
  91. /* rampUp - add stars to the galaxy.
  92.  *
  93.  */
  94. rampUp(toAdd)int toAdd;{
  95.         register struct star *aStar;
  96.         struct star *galaxyEnd;
  97.         register int i, size;
  98.  
  99.     galaxyEnd = galaxy + inUse + toAdd;
  100.     for (aStar = galaxy+inUse; aStar < galaxyEnd; aStar++) {
  101.         aStar->pos.x = Random() % xyspan;
  102.         aStar->pos.y = Random() % xyspan;
  103.         aStar->pos.z = abs(Random() % zspan);
  104.         /* set up stars */
  105.         if (aStar->pos.z == 0) aStar->pos.z =1;
  106.         /*draw all stars with one-point perspective using
  107.                   the formulae x' = x/z; y' = y/z */
  108.         DrawStar(srcXor,
  109.                 aStar->draw.x = aStar->pos.x/aStar->pos.z,
  110.                 aStar->draw.y = aStar->pos.y/aStar->pos.z,
  111.                 aStar->draw.z = StarSize(aStar->pos.z));
  112.     }
  113.     inUse += toAdd;
  114. }
  115.  
  116. /* rampDn - remove stars from the galaxy
  117.  *
  118.  */
  119. rampDn(toSub)int toSub;{
  120.         register struct star *aStar;
  121.         struct star *galaxyEnd;
  122.         register int i, size;
  123.  
  124.     galaxyEnd = galaxy + inUse;
  125.     for (aStar = galaxy + inUse - toSub; aStar < galaxyEnd; aStar++) {
  126.         /* undraw all stars with one-point perspective using
  127.                   the formulae x' = x/z; y' = y/z */
  128.         DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);
  129.     }
  130.     inUse -= toSub;
  131. }
  132.  
  133. /* update - do one animation step 
  134.  * update the model for all stars, and redraw those that need it.
  135.  */
  136.  
  137. update(){
  138.     register struct star *aStar;
  139.     struct star *galaxyEnd;
  140.     struct starRec new;
  141.  
  142.     galaxyEnd = galaxy + inUse;
  143.     for (aStar = galaxy; aStar < galaxyEnd; aStar++) {
  144.  
  145.         aStar->pos.z -= 1;    /*Update z coordinate */
  146.  
  147.         if (aStar->pos.z <= 0){
  148.             /* if star has passed us, make a new one on horizon */
  149.             aStar->pos.z = zspan;
  150.             aStar->pos.x = Random() % xyspan;
  151.             aStar->pos.y = Random() % xyspan;
  152.         }
  153.  
  154.         new.x = aStar->pos.x / aStar->pos.z,
  155.         new.y = aStar->pos.y / aStar->pos.z,
  156.         new.z = StarSize(aStar->pos.z);
  157.         if(new.x != aStar->draw.x ||    /* if it moved, then show it */
  158.             new.y != aStar->draw.y ||
  159.             new.z != aStar->draw.z){
  160.             DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);/*undraw new*/
  161.             aStar->draw = new;
  162.             DrawStar(srcXor, aStar->draw.x, aStar->draw.y, aStar->draw.z);/*draw new*/
  163.         }
  164.     }
  165. }
  166.  
  167. /* Xor the pixel at coordinates x, y (direct screen memory access!)
  168.  */
  169.  
  170. void FlipPixel(x, y)register int x, y;{
  171.   register GrafPtr myPort;
  172.   register QDPtr theByte;
  173.   register QDByte thePixel;
  174.   
  175.   myPort = myWindow;
  176.   if(     x >= myPort->portBits.bounds.left    &&
  177.           y >= myPort->portBits.bounds.top    &&
  178.           x < myPort->portBits.bounds.right    &&
  179.           y < myPort->portBits.bounds.bottom){
  180.     y -= myPort->portBits.bounds.top;
  181.     x -= myPort->portBits.bounds.left;
  182.     theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
  183.     thePixel = 0x80 >> (x & 7);
  184.     *theByte ^= thePixel;
  185.   }
  186. }
  187. /* Set the pixel at coordinates x, y (direct screen memory access!)
  188.  */
  189.  
  190. void OnPixel(x, y)register int x, y;{
  191.   register GrafPtr myPort;
  192.   register QDPtr theByte;
  193.   register QDByte thePixel;
  194.   
  195.   myPort = myWindow;
  196.   if(     x >= myPort->portBits.bounds.left    &&
  197.           y >= myPort->portBits.bounds.top    &&
  198.           x < myPort->portBits.bounds.right    &&
  199.           y < myPort->portBits.bounds.bottom){
  200.     y -= myPort->portBits.bounds.top;
  201.     x -= myPort->portBits.bounds.left;
  202.     theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
  203.     thePixel = 0x80 >> (x & 7);
  204.     *theByte |= thePixel;
  205.   }
  206. }
  207.  
  208. /* Clear the pixel at coordinates x, y (direct screen memory access!)
  209.  */
  210.  
  211. void OffPixel(x, y)register int x, y;{
  212.   register GrafPtr myPort;
  213.   register QDPtr theByte;
  214.   register QDByte thePixel;
  215.   
  216.   myPort = myWindow;
  217.   if(     x >= myPort->portBits.bounds.left    &&
  218.           y >= myPort->portBits.bounds.top    &&
  219.           x < myPort->portBits.bounds.right    &&
  220.           y < myPort->portBits.bounds.bottom){
  221.     y -= myPort->portBits.bounds.top;
  222.     x -= myPort->portBits.bounds.left;
  223.     theByte = myPort->portBits.baseAddr + (y * myPort->portBits.rowBytes) + (x >> 3);
  224.     thePixel = 0xFF7F >> (x & 7);
  225.     *theByte &= thePixel;
  226.   }
  227. }
  228.  
  229. /* bitmaps for DrawStar */
  230. char data1[] = "\377";                    /* must be 2 chars long */
  231. char data2[] = "\137\337\377\377\137";    /* must be 6 chars long */
  232. short int data3[] = { 
  233.     0x3000, 
  234.     0x7C00,
  235.     0x7C00, 
  236.     0x7C00,
  237.     0x3000 
  238. };    /* must be 10 chars long */
  239. short int data4[] = {
  240.     0x3C00,
  241.     0x7E00,
  242.     0xFF00,
  243.     0xFF00,
  244.     0xFD00,
  245.     0x7A00,
  246.     0x3C00,
  247. };
  248.  
  249. /* As a star grows, we want its center to stay its center.
  250.  * Copybits will keep the left corner the left corner.
  251.  * The extra rect here is to make it fast to compute the center
  252.  *
  253.  * This data structure gets its run-time initialization done in doMain
  254.  */
  255. typedef struct { BitMap b; Rect r; } BitStuff;
  256. BitStuff srcBits[] = {
  257.     {{ 0L, 2, {0, 0, 1, 1}}, {0, 0, 1, 1} },
  258.     {{ 0L, 2, {0, 0, 1, 1}}, {0, 0, 1, 1} },
  259.     {{ 0L, 2, {0, 0, 3, 3}}, {-1, -1, 2, 2} },    
  260.     {{ 0L, 2, {0, 0, 5, 5}}, {-2, -2, 3, 3} },
  261.     {{ 0L, 2, {0, 0, 7, 8}}, {-3, -4, 4, 4} },
  262. } ;
  263.  
  264. /* DrawStar - actually draw a star.
  265.  * (this version optimizes for the small star cases)
  266.  */
  267.  
  268. void DrawStar(tMode, x, y, size){
  269.     register void (*ChangePixel)();
  270.     register BitStuff *srcPtr;
  271.     Rect destRect;
  272.  
  273.     if(tMode == srcXor)
  274.         ChangePixel = FlipPixel;
  275.     else if(tMode == srcOr)
  276.         ChangePixel = OnPixel;
  277.     else
  278.         ChangePixel = OffPixel;
  279.  
  280.     switch( size ){
  281.     case 2 :
  282.         (*ChangePixel)(x, y-1); (*ChangePixel)(x, y+1);
  283.         (*ChangePixel)(x-1, y); (*ChangePixel)(x+1, y);    /* note, we fall through */
  284.     case 1  :
  285.         (*ChangePixel)(x, y); break;
  286.     default :
  287.         srcPtr = srcBits + size;
  288.     
  289.         destRect.left    = x + srcPtr->r.left;
  290.         destRect.top    = y + srcPtr->r.top;
  291.         destRect.right    = x + srcPtr->r.right;
  292.         destRect.bottom    = y + srcPtr->r.bottom;
  293.     
  294.         CopyBits(&srcPtr->b,        &myWindow->portBits,
  295.                 &srcPtr->b.bounds,    &destRect,
  296.                 tMode,                0L);
  297.     }
  298. }
  299.  
  300.  
  301. /* speed up by displaying fewer stars, down by displaying more.
  302.  *
  303.  */
  304. Throttle(c)int c;{
  305.     int toUse;
  306.  
  307.     toUse =  numStars * ( (2*(c & 15) + 1))  / 32;
  308.     if(toUse > inUse)rampUp(toUse - inUse);
  309.     if(toUse < inUse)rampDn(inUse - toUse);
  310. }
  311.  
  312. /* SetThrottle - permanently change Throttle setting
  313.  * handle proprogation of Throttle setting to disk, and call
  314.  * throttle to actually change the number of stars.
  315.  *
  316.  */
  317. SetThrottle(c)int c;{
  318.     LoadResource(theThrottle);
  319.     if(**theThrottle != c){
  320.         **theThrottle = c;
  321.         HNoPurge(theThrottle);
  322.         ChangedResource(theThrottle);
  323.     }
  324.     HyperThrottle(c);
  325. }
  326. /***** hyperspace support routines ******/
  327. /* HyperUpdate - animate galaxy off the screen 
  328.  * update the model for all stars, and redraw those that need it.
  329.  *
  330.  * Note: I chose to fix the hyper effect starsize at 1.
  331.  */
  332.  
  333. HyperUpdate(tMode, galaxyStart, galaxyEnd)
  334.     int tMode;
  335.     struct star *galaxyStart, *galaxyEnd;
  336. {
  337.     register struct star *aStar;
  338.     struct starRec new;
  339.     int changed;
  340.  
  341.      changed = 1;
  342.      while(changed){
  343.          changed = 0;
  344.         for (aStar = galaxyStart; aStar < galaxyEnd; aStar++) {
  345.     
  346.             aStar->pos.z -= 2;    /*Update z coordinate */
  347.     
  348.             if (aStar->pos.z > 0){
  349.                 new.x = aStar->pos.x / aStar->pos.z,
  350.                 new.y = aStar->pos.y / aStar->pos.z,
  351.                 new.z = 1; /* StarSize(aStar->pos.z); */
  352.                 if(new.x != aStar->draw.x ||    /* if it moved, then show it */
  353.                     new.y != aStar->draw.y ||
  354.                     new.z != aStar->draw.z){
  355.                     changed = 1;    /* a star visibly moved */
  356.                     aStar->draw = new;
  357.                     DrawStar(tMode, 
  358.                         aStar->draw.x, 
  359.                         aStar->draw.y, 
  360.                         aStar->draw.z);    /*draw new*/
  361.                 }
  362.             }
  363.         }
  364.     }
  365. }
  366.  
  367. void HyperThrottle(c)int c;{
  368.     struct star *HiGalaxy, *galaxyEnd;
  369.     register struct star *aStar, *destStar;
  370.     galaxyEnd = galaxy + numStars/16;
  371.     HiGalaxy = galaxy + numStars - numStars/16 - 1;
  372.     aStar = galaxy; destStar = HiGalaxy; 
  373.     rampDn(inUse);
  374.     while(aStar < galaxyEnd){
  375.          *destStar++ = *aStar++;
  376.     }
  377.     HyperUpdate(srcBic, galaxy, galaxyEnd);                    /* draw 'em. */
  378.     inUse = 0;
  379.     HyperUpdate(srcOr, HiGalaxy, HiGalaxy + numStars/16);    /* Erase 'em */
  380.     Throttle(c);
  381. }
  382.  
  383. /* To Un-desk-accessory-ify this, just un-comment out the commented out
  384.  * lines, and make this the main procedure
  385.  *
  386.  * It is important to me that the numbers 512, 342 not appear in my code.
  387.  * some people still have lisa's
  388.  */
  389. doMain()
  390. {    EventRecord myEvent;
  391.     long int space;
  392.     int i;
  393.     Rect bigRect;
  394.  
  395.     SetRect(&bigRect, 0, 0, 10000, 10000);
  396.     myWindow = NewWindow(0L, &bigRect, "\p",
  397.                 0, 0, (char*) -1, 1, 0L);
  398.     space = CompactMem((long) maxSize) / sizeof(struct star);
  399.     if(space > 1000)        /* space for other things */
  400.         space -= 1000;
  401.     if(space < numStars)
  402.         numStars = space;
  403.      galaxy = (struct star *) NewPtr(numStars-- * (long) sizeof(struct star));
  404.      if(galaxy != 0L){
  405. /*        InitGraf(&thePort);     /* do inits */
  406. /*        InitWindows();            */
  407. /*        SetCursor(&arrow);        */
  408.         FlushEvents(everyEvent,0);
  409.         HideCursor();
  410.         SetPort(myWindow);
  411.         ShowWindow(myWindow);
  412.         InitPort(myWindow);    /* set port to entire screen, no menubar! */
  413.         BackPat(myWindow->pnPat);    /* black */
  414.         EraseRect(&myWindow->portRect);        /* flip screen to black */
  415.         SetOrigin(-myWindow->portRect.right / 2,
  416.                 -myWindow->portRect.bottom / 2);
  417.  
  418.  
  419.         PenMode(patXor); /*use exclusive-or drawing to ease programming */
  420.         if(myWindow->portBits.baseAddr != 0L) {
  421.             srcBits[0].b.baseAddr = (QDPtr) &data1;
  422.             srcBits[1].b.baseAddr = (QDPtr) &data1;
  423.             srcBits[2].b.baseAddr = (QDPtr) &data2;
  424.             srcBits[3].b.baseAddr = (QDPtr) &data3;
  425.             srcBits[4].b.baseAddr = (QDPtr) &data4;
  426.  
  427.             /* initialize galaxy */
  428.             theThrottle = (IntHandle) GetResource('GNRL', RsrcID(0));
  429.             HPurge(theThrottle);
  430.             Throttle(**theThrottle);
  431.  
  432.             /* do until mousedown, or until user hits a command key */
  433.             myEvent.what = nullEvent;
  434.             while( ! ( (myEvent.what == mouseDown) || 
  435.                 (myEvent.what == keyDown && (myEvent.modifiers & cmdKey)) )){
  436.                 if(myEvent.what == keyDown){
  437.                     SetThrottle((int) myEvent.message & 0xFF);
  438.                 }
  439.                 update(); /* animate until moused */
  440.                 SystemTask();
  441.                 GetNextEvent(mDownMask+keyDownMask, &myEvent);
  442.             }
  443.  
  444.         }
  445.  
  446.         DisposPtr( (Ptr) galaxy);
  447.         DisposeWindow(myWindow);
  448.         DrawMenuBar();
  449.         ShowCursor();
  450.     }
  451. }
  452. /*
  453.  *  main program
  454.  *
  455.  *  The first two arguments are the values passed in registers A0/A1
  456.  *  to an assembly-language desk accessory.  The third argument is a
  457.  *  selector indicating which entry point was called.
  458.  */
  459. DCtlPtr dce;    /* desk acc global to get at device control entry */
  460.  
  461. main(p, d, n)
  462.     cntrlParam *p;    /*  ==> parameter block  */
  463.     DCtlPtr d;        /*  ==> device control entry  */
  464.     int n;        /*  entry point selector  */
  465. {    
  466.     if (d->dCtlStorage == 0) {
  467.         if (n == 0) {    /*  open, but no data  */
  468.             SysBeep(3);
  469.             CloseDriver(d->dCtlRefNum);
  470.         }
  471.         return(0);
  472.     }
  473.     dce = d;
  474.     /*  dispatch  */
  475.     if( n == 0){    /* i.e, an Open */
  476.         doMain();
  477.         CloseDriver(d->dCtlRefNum);
  478.     }
  479. }
  480. /* ---------- resource handling ---------- */
  481. /*
  482.  *  RsrcID - compute ID of owned resource
  483.  *
  484.  *  This is a magic formula by which we can compute the IDs of our
  485.  *  resources no matter what driver number Font/DA-Mover has assigned
  486.  *  us.  See the Resource Manager chapter of Inside Macintosh for more
  487.  *  information about "owned" resources.
  488.  */
  489.  
  490. int RsrcID(id)int id;{
  491.     return 0xC000 + (~dce->dCtlRefNum << 5) + id;
  492. }
  493.